package com.kcht.itsed.mws.alefacade.stdfacade.impl;

import com.kcht.itsed.mws.alefacade.exceptions.DuplicateNameException;
import com.kcht.itsed.mws.alefacade.exceptions.InUseException;
import com.kcht.itsed.mws.alefacade.exceptions.NoSuchNameException;
import com.kcht.itsed.mws.alefacade.exceptions.ValidationException;
import com.kcht.itsed.mws.alefacade.stdfacade.ALEPR;
import com.kcht.itsed.mws.devicescheduler.facade.IPhysicalReaderLinkManager;
import com.kcht.itsed.mws.extendalemodel.PRSpec;
import com.kcht.itsed.mws.extendalemodel.PhysicalReaderLinkState;
import com.kcht.itsed.mws.extendmodel.jpa.PhysicalReaderEntity;
import com.kcht.itsed.mws.persist.dao.IPhysicalReaderDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * Created by God on 2016/4/20.
 */
@Component
public class ALEPR_IMPL implements ALEPR {
    @Autowired
    private IPhysicalReaderDao prDao;

    @Autowired
    private IPhysicalReaderLinkManager  prLinkManager;
    
    @Override
    public void define(String name, PRSpec reader) throws DuplicateNameException, ValidationException {
        Optional<PhysicalReaderEntity> find = prDao.findByName(name);
        if (find.isPresent())throw new DuplicateNameException("Physical reader name ["+name+"] already existed.");
        PhysicalReaderEntity physicalReader = prSpec2PhysicalReader(name,reader);
        physicalReader.setId(null);
        prDao.insert(physicalReader);
		prLinkManager.addPhysicalReader(reader);
    }

    private PhysicalReaderEntity prSpec2PhysicalReader(String name,PRSpec spec) {
		PhysicalReaderEntity pre = new PhysicalReaderEntity();
		pre.setPrSpec(spec);
		pre.setReaderName(name);
		pre.setReaderClass(spec.getReaderClass());
		pre.setReaderId(spec.getReaderId());
		pre.setReaderIp(spec.getReaderIp());
		return pre;
	}

    @Override
    public void update(String name, PRSpec prSpec) throws NoSuchNameException, ValidationException, InUseException {
        Optional<PhysicalReaderEntity> find = prDao.findByName(name);
        find.orElseThrow(()-> new NoSuchNameException("Physical reader name ["+name+"] not existed."));
	    PhysicalReaderEntity update = prSpec2PhysicalReader(name,prSpec);
        update.setId(find.get().getId());
        prDao.updateById(update);
		prLinkManager.addPhysicalReader(prSpec);
    }

    @Override
    public void undefine(String name) throws NoSuchNameException, InUseException {
        Optional<PhysicalReaderEntity> find = prDao.findByName(name);
        find.orElseThrow(()->new NoSuchNameException("No physical reader name["+name+"]"));
        //检查在用
        if(prLinkManager.isPhysicalReaderInUse(find.get().getReaderIp())) 
        	throw new InUseException("Physical reader name["+name+"] with ip ["+find.get().getReaderIp()+"] is in use.");
        	
		//TODO 检查引用
        prDao.deleteById(find.get().getId());
    }

    @Override
    public List<String> getPhysicalReaderNames() {
        List<PhysicalReaderEntity> all = prDao.getAllPRs();
        return all.stream().map(r -> r.getReaderName()+" (id="+r.getReaderId()+")").collect(Collectors.toList());
    }

    @Override
    public PRSpec getPRSpec(String name) throws NoSuchNameException {
        Optional<PhysicalReaderEntity> find = prDao.findByName(name);
        find.orElseThrow(()->new NoSuchNameException("No physical reader name ["+name+"]"));
        return find.get().getPrSpec();
    }

	@Override
	public List<PhysicalReaderLinkState> getPhysicalReaderLinkState() {
		return prDao.getAllPRs().stream().map(pr->{
			PhysicalReaderLinkState pls = new PhysicalReaderLinkState();
			pls.setIp(pr.getReaderIp());
			pls.setReaderName(pr.getReaderName());
			pls.setLinkStateDesc(prLinkManager.getReaderLinkState(pr.getReaderIp()));
			return pls;
		}).collect(Collectors.toList());
	}

	@Override
	public List<PhysicalReaderLinkState> getDisconnectedPhysicalReader() {
		return getPhysicalReaderLinkState().stream()
				.filter(pls->!pls.getLinkStateDesc().equals("CONNECTED"))
				.collect(Collectors.toList());
	}
    
}
